home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / pbmplus / pgm / pgmtopbm.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  7KB  |  267 lines

  1. /* pgmtopbm.c - read a portable graymap and write a portable bitmap
  2. **
  3. ** Copyright (C) 1989 by Jef Poskanzer.
  4. **
  5. ** Permission to use, copy, modify, and distribute this software and its
  6. ** documentation for any purpose and without fee is hereby granted, provided
  7. ** that the above copyright notice appear in all copies and that both that
  8. ** copyright notice and this permission notice appear in supporting
  9. ** documentation.  This software is provided "as is" without express or
  10. ** implied warranty.
  11. */
  12.  
  13. #include "pgm.h"
  14. #include "pbm.h"
  15. #include "dithers.h"
  16.  
  17. void
  18. main( argc, argv )
  19.     int argc;
  20.     char* argv[];
  21.     {
  22.     FILE* ifp;
  23.     gray* grayrow;
  24.     register gray* gP;
  25.     bit* bitrow;
  26.     register bit* bP;
  27.     int argn, rows, cols, format, row, col, limitcol;
  28.     float fthreshval;
  29.     gray maxval;
  30.     char* usage = "[-floyd|-fs | -threshold | -dither8|-d8 |\n     -cluster3|-c3|-cluster4|-c4|-cluster8|-c8] [-value <val>] [pgmfile]";
  31.     int halftone;
  32. #define QT_FS 1
  33. #define QT_THRESH 2
  34. #define QT_DITHER8 3
  35. #define QT_CLUSTER3 4
  36. #define QT_CLUSTER4 5
  37. #define QT_CLUSTER8 6
  38.     long threshval, sum;
  39.     long* thiserr;
  40.     long* nexterr;
  41.     long* temperr;
  42. #define FS_SCALE 1024
  43. #define HALF_FS_SCALE 512
  44.     int fs_direction;
  45.  
  46.     pgm_init( &argc, argv );
  47.  
  48.     argn = 1;
  49.     halftone = QT_FS;    /* default quantization is Floyd-Steinberg */
  50.     fthreshval = 0.5;
  51.  
  52.     while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
  53.     {
  54.     if ( pm_keymatch( argv[argn], "-fs", 2 ) ||
  55.          pm_keymatch( argv[argn], "-floyd", 2 ) )
  56.         halftone = QT_FS;
  57.     else if ( pm_keymatch( argv[argn], "-threshold", 2 ) )
  58.         halftone = QT_THRESH;
  59.     else if ( pm_keymatch( argv[argn], "-dither8", 2 ) ||
  60.               pm_keymatch( argv[argn], "-d8", 3 ) )
  61.         halftone = QT_DITHER8;
  62.     else if ( pm_keymatch( argv[argn], "-cluster3", 9 ) ||
  63.               pm_keymatch( argv[argn], "-c3", 3 ) )
  64.         halftone = QT_CLUSTER3;
  65.     else if ( pm_keymatch( argv[argn], "-cluster4", 9 ) ||
  66.               pm_keymatch( argv[argn], "-c4", 3 ) )
  67.         halftone = QT_CLUSTER4;
  68.     else if ( pm_keymatch( argv[argn], "-cluster8", 9 ) ||
  69.               pm_keymatch( argv[argn], "-c8", 3 ) )
  70.         halftone = QT_CLUSTER8;
  71.     else if ( pm_keymatch( argv[argn], "-value", 2 ) )
  72.         {
  73.         ++argn;
  74.         if ( argn == argc || sscanf( argv[argn], "%f", &fthreshval ) != 1 ||
  75.          fthreshval < 0.0 || fthreshval > 1.0 )
  76.         pm_usage( usage );
  77.         }
  78.     else
  79.         pm_usage( usage );
  80.     ++argn;
  81.     }
  82.  
  83.     if ( argn != argc )
  84.     {
  85.     ifp = pm_openr( argv[argn] );
  86.     ++argn;
  87.     }
  88.     else
  89.     ifp = stdin;
  90.  
  91.     if ( argn != argc )
  92.     pm_usage( usage );
  93.  
  94.     pgm_readpgminit( ifp, &cols, &rows, &maxval, &format );
  95.     grayrow = pgm_allocrow( cols );
  96.  
  97.     pbm_writepbminit( stdout, cols, rows, 0 );
  98.     bitrow = pbm_allocrow( cols );
  99.  
  100.     /* Initialize. */
  101.     switch ( halftone )
  102.     {
  103.     case QT_FS:
  104.     /* Initialize Floyd-Steinberg error vectors. */
  105.     thiserr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  106.     nexterr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  107.     srandom( (int) ( time( 0 ) ^ getpid( ) ) );
  108.     for ( col = 0; col < cols + 2; ++col )
  109.         thiserr[col] = ( random( ) % FS_SCALE - HALF_FS_SCALE ) / 4;
  110.         /* (random errors in [-FS_SCALE/8 .. FS_SCALE/8]) */
  111.     fs_direction = 1;
  112.     threshval = fthreshval * FS_SCALE;
  113.     break;
  114.  
  115.     case QT_THRESH:
  116.     threshval = fthreshval * maxval + 0.999999;
  117.     break;
  118.  
  119.     case QT_DITHER8:
  120.     /* Scale dither matrix. */
  121.     for ( row = 0; row < 16; ++row )
  122.         for ( col = 0; col < 16; ++col )
  123.         dither8[row][col] = dither8[row][col] * ( maxval + 1 ) / 256;
  124.     break;
  125.  
  126.     case QT_CLUSTER3:
  127.     /* Scale order-3 clustered dither matrix. */
  128.     for ( row = 0; row < 6; ++row )
  129.         for ( col = 0; col < 6; ++col )
  130.         cluster3[row][col] = cluster3[row][col] * ( maxval + 1 ) / 18;
  131.     break;
  132.  
  133.     case QT_CLUSTER4:
  134.     /* Scale order-4 clustered dither matrix. */
  135.     for ( row = 0; row < 8; ++row )
  136.         for ( col = 0; col < 8; ++col )
  137.         cluster4[row][col] = cluster4[row][col] * ( maxval + 1 ) / 32;
  138.     break;
  139.  
  140.     case QT_CLUSTER8:
  141.     /* Scale order-8 clustered dither matrix. */
  142.     for ( row = 0; row < 16; ++row )
  143.         for ( col = 0; col < 16; ++col )
  144.         cluster8[row][col] = cluster8[row][col] * ( maxval + 1 ) / 128;
  145.     break;
  146.  
  147.     default:
  148.     pm_error( "can't happen" );
  149.     }
  150.  
  151.     for ( row = 0; row < rows; ++row )
  152.     {
  153.     pgm_readpgmrow( ifp, grayrow, cols, maxval, format );
  154.  
  155.     switch ( halftone )
  156.         {
  157.         case QT_FS:
  158.         for ( col = 0; col < cols + 2; ++col )
  159.         nexterr[col] = 0;
  160.         if ( fs_direction )
  161.         {
  162.         col = 0;
  163.         limitcol = cols;
  164.         gP = grayrow;
  165.         bP = bitrow;
  166.         }
  167.         else
  168.         {
  169.         col = cols - 1;
  170.         limitcol = -1;
  171.         gP = &(grayrow[col]);
  172.         bP = &(bitrow[col]);
  173.         }
  174.         do
  175.         {
  176.         sum = ( (long) *gP * FS_SCALE ) / maxval + thiserr[col + 1];
  177.         if ( sum >= threshval )
  178.             {
  179.             *bP = PBM_WHITE;
  180.             sum = sum - threshval - HALF_FS_SCALE;
  181.             }
  182.         else
  183.             *bP = PBM_BLACK;
  184.  
  185.         if ( fs_direction )
  186.             {
  187.             thiserr[col + 2] += ( sum * 7 ) / 16;
  188.             nexterr[col    ] += ( sum * 3 ) / 16;
  189.             nexterr[col + 1] += ( sum * 5 ) / 16;
  190.             nexterr[col + 2] += ( sum     ) / 16;
  191.  
  192.             ++col;
  193.             ++gP;
  194.             ++bP;
  195.             }
  196.         else
  197.             {
  198.             thiserr[col    ] += ( sum * 7 ) / 16;
  199.             nexterr[col + 2] += ( sum * 3 ) / 16;
  200.             nexterr[col + 1] += ( sum * 5 ) / 16;
  201.             nexterr[col    ] += ( sum     ) / 16;
  202.  
  203.             --col;
  204.             --gP;
  205.             --bP;
  206.             }
  207.         }
  208.         while ( col != limitcol );
  209.         temperr = thiserr;
  210.         thiserr = nexterr;
  211.         nexterr = temperr;
  212.         fs_direction = ! fs_direction;
  213.         break;
  214.  
  215.         case QT_THRESH:
  216.         for ( col = 0, gP = grayrow, bP = bitrow; col < cols; ++col, ++gP, ++bP )
  217.         if ( *gP >= threshval )
  218.             *bP = PBM_WHITE;
  219.         else
  220.             *bP = PBM_BLACK;
  221.         break;
  222.  
  223.         case QT_DITHER8:
  224.         for ( col = 0, gP = grayrow, bP = bitrow; col < cols; ++col, ++gP, ++bP )
  225.         if ( *gP >= dither8[row % 16][col % 16] )
  226.             *bP = PBM_WHITE;
  227.         else
  228.             *bP = PBM_BLACK;
  229.         break;
  230.  
  231.         case QT_CLUSTER3:
  232.         for ( col = 0, gP = grayrow, bP = bitrow; col < cols; ++col, ++gP, ++bP )
  233.         if ( *gP >= cluster3[row % 6][col % 6] )
  234.             *bP = PBM_WHITE;
  235.         else
  236.             *bP = PBM_BLACK;
  237.         break;
  238.  
  239.         case QT_CLUSTER4:
  240.         for ( col = 0, gP = grayrow, bP = bitrow; col < cols; ++col, ++gP, ++bP )
  241.         if ( *gP >= cluster4[row % 8][col % 8] )
  242.             *bP = PBM_WHITE;
  243.         else
  244.             *bP = PBM_BLACK;
  245.         break;
  246.  
  247.         case QT_CLUSTER8:
  248.         for ( col = 0, gP = grayrow, bP = bitrow; col < cols; ++col, ++gP, ++bP )
  249.         if ( *gP >= cluster8[row % 16][col % 16] )
  250.             *bP = PBM_WHITE;
  251.         else
  252.             *bP = PBM_BLACK;
  253.         break;
  254.  
  255.         default:
  256.         pm_error( "can't happen" );
  257.         }
  258.  
  259.     pbm_writepbmrow( stdout, bitrow, cols, 0 );
  260.     }
  261.  
  262.     pm_close( ifp );
  263.     pm_close( stdout );
  264.  
  265.     exit( 0 );
  266.     }
  267.